home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / ups / apcd-0.5 / apcd-0 / apcd.c next >
C/C++ Source or Header  |  1995-11-07  |  15KB  |  671 lines

  1. /*
  2.  * apcd.c - Daemon for the APC Smart UPS
  3.  *
  4.  * Copyright (c) 1995 Pavel Korensky
  5.  * All rights reserved.
  6.  *
  7.  * Permission is hereby granted, without written agreement and without
  8.  * license or royalty fees, to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose, provided that the
  10.  * above copyright notice and the following two paragraphs appear in
  11.  * all copies of this software.
  12.  * 
  13.  * IN NO EVENT SHALL PAVEL KORENSKY BE LIABLE TO ANY PARTY FOR
  14.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  15.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF PAVEL
  16.  * KORENSKY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  17.  *
  18.  * PAVEL KORENSKY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  19.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  20.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  21.  * ON AN "AS IS" BASIS, AND PAVEL KORENSKY HAS NO OBLIGATION TO
  22.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  23.  */
  24.  
  25. /*    
  26.  * Version:
  27.  *    
  28.  * $Id: apcd.c,v 1.7 1995/11/07 12:40:03 root Exp root $
  29.  *    
  30.  *    
  31.  * History:
  32.  *    
  33.  * $Log: apcd.c,v $
  34.  * Revision 1.7  1995/11/07  12:40:03  root
  35.  * Version 0.5 Beta, uploaded to the sunsite
  36.  *
  37.  * Revision 1.6  1995/11/01  15:25:28  root
  38.  * Several adaptations for clien/server - NOT FUNCTIONAL
  39.  *
  40.  * Revision 1.5  1995/05/23  07:25:08  root
  41.  * First public ALPHA version
  42.  *
  43.  * Revision 1.4  1995/05/23  01:07:40  root
  44.  * Parameters are on the command line, instead of config.h file
  45.  *
  46.  * Revision 1.3  1995/05/23  00:25:43  root
  47.  * System shutdown with UPS switch off was added
  48.  *
  49.  * Revision 1.2  1995/05/21  21:10:56  root
  50.  * Some small fixes
  51.  *
  52.  * Revision 1.1  1995/05/21  20:15:13  root
  53.  * Initial revision
  54.  *
  55.  *
  56.  *
  57.  *
  58.  *    
  59.  */    
  60.  
  61.  
  62. #include "apcd.h"
  63. #include "version.h"
  64.  
  65. static char *version="$Id: apcd.c,v 1.7 1995/11/07 12:40:03 root Exp root $";
  66.  
  67. UPSINFO        myUPS;
  68. FILE        *valfile;
  69. FILE        *UPSlogfile;
  70. int        killme, battlow;
  71. int        slave = 0;
  72. int        port;
  73. int        socketfd,newsocketfd;
  74. char        *use_port;
  75. char        *master_name;
  76. char        *logfilename;
  77. char        *slaves[MAX_SLAVES];
  78. int        num_slaves = 0;
  79. int        power_timer = 10;
  80. int        log_timer = 30;
  81. int        log_counter = 0;
  82. int        alarmup,alarmdown,pending,alarmcount,wasmsg;
  83. int        gottimeout = 0;
  84. int        mastertimeout = 0;
  85. int        gotpowerok = 0;
  86. int        masterbatlow = 0;
  87. struct termios    oldtio, newtio;
  88.  
  89.  
  90. void main(int argc, char *argv[])
  91. {
  92.     char     msg[100];
  93.     int    i;
  94.     time_t    cas;
  95.  
  96.     time(&cas);
  97.     strftime(msg,100,"%b %d %X",localtime(&cas));
  98.     printf("%s apcd:\n",msg);
  99.     use_port=calloc(100,sizeof(char));
  100.     master_name=calloc(100,sizeof(char));
  101.     logfilename=calloc(100,sizeof(char));
  102.     for(i=0;i<=MAX_SLAVES;i++) slaves[i]=calloc(100,sizeof(char)); 
  103.  
  104.       if(parse_config()==0) {
  105.         printf("\nConfiguration file is bad or missing\n");
  106.         exit(0);
  107.     }
  108.     if(slave==2) {
  109.         printf("APC SmartUPS daemon started on port %s with timeout %d mins.\n",use_port,power_timer); 
  110.         printf("APC SmartUPS daemon logging interval %d seconds.\n",log_timer);
  111.         for(i=0;i<num_slaves;i++) printf("Slave: %s\n",slaves[i]);
  112.     }
  113.     else printf("APC SmartUPS daemon started in slave mode. Master is %s\n",master_name);
  114.     killme = 0;
  115.     /* Initialize system log */
  116.     openlog("apcd", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_LOCAL2);
  117.     /* If we are master, we are responsible for UPS statistic log */
  118.     if(slave == 2) {
  119.         UPSlogfile=fopen(logfilename,"a");        
  120.     }
  121.         
  122.     /* Become daemon */
  123.     start_daemon();
  124.     signal_setup();    
  125.     syslog(LOG_INFO,"Starting apcd version %s",VERSION);
  126.     if(slave==2) {
  127.         syslog(LOG_INFO,"Master mode port %s timeout %d",use_port,power_timer);
  128.         syslog(LOG_INFO,"UPS statistics in %s",logfilename);
  129.         for(i=0;i<num_slaves;i++) syslog(LOG_INFO,"Slave: %s",slaves[i]);
  130.     }
  131.     if(slave==1) syslog(LOG_INFO,"Slave mode. Master is %s",master_name);
  132.     if(slave==2) setup_tty();
  133.     battlow=0;
  134.     alarmup=0;
  135.     alarmdown=0;
  136.     pending=0;
  137.     wasmsg=0;
  138.     /* Open socket for network communication */
  139.     if(slave == 1) {
  140.         if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  141.             syslog(LOG_ERR,"Can't open stream socket");
  142.         }
  143.     }
  144.     if(slave == 2) {
  145.         prepare_master();
  146.     }
  147.     if(slave == 1) prepare_slave();           /* If slave, do some network stuff */
  148.     if(slave == 1) {
  149.         while(!killme) {
  150.             if(get_master_message(newsocketfd) == 0) {
  151.                 if(gottimeout) {
  152.                     gottimeout = 0;
  153.                     syslog(LOG_INFO,"Power failure, %d minutes to shutdown",mastertimeout);
  154.                     if(mastertimeout == 0) go_down();
  155.                     else {    
  156.                         sprintf(msg,"\n\nAPC Daemon: Power failure, system will go down in %d minutes.\n",mastertimeout); 
  157.                         mesall(msg);
  158.                         wasmsg=1;
  159.                     }
  160.                 }
  161.                 if(gotpowerok) {
  162.                     gotpowerok = 0;
  163.                     syslog(LOG_INFO,"Power restored, shutdown cancelled");
  164.                     if(wasmsg) {
  165.                         sprintf(msg,"\n\nAPC Daemon: Power restored, shutdown cancelled.\n");
  166.                         mesall(msg);
  167.                         wasmsg=0;
  168.                     }
  169.                 }
  170.                 if(masterbatlow) go_down_batt();
  171.                 
  172.             }
  173.         }
  174.     }
  175.     else {    
  176.         while(!killme) {
  177.             fillUPS(port,&myUPS); 
  178.             sleep(1);
  179.             if (pending) {
  180.                 alarmcount--;
  181.                 if (alarmcount == 0) {
  182.                     send_to_slaves(0);
  183.                     go_down();
  184.                     pending=0;
  185.                 }
  186.                 if(((alarmcount % 60) == 0) && (alarmcount != 0)) {
  187.                     send_to_slaves(alarmcount);
  188.                     sprintf(msg,"\n\nAPC Daemon: Power failure, system will go down in %d minutes.\n",alarmcount/60);
  189.                     mesall(msg);
  190.                     wasmsg=1;
  191.                 }    
  192.             }
  193.             if (alarmup) {
  194.                 if(!pending) {
  195.                     alarmcount=power_timer*60;
  196.                     pending=1;
  197.                 }
  198.                 alarmup=0;
  199.             }
  200.             if (alarmdown) {
  201.                 if(wasmsg) {
  202.                     send_to_slaves(-1);
  203.                     sprintf(msg,"\n\nAPC Daemon: Power restored, shutdown cancelled\n");
  204.                     mesall(msg);
  205.                     wasmsg=0;
  206.                 }
  207.                 alarmcount=0;
  208.                 pending=0;
  209.                 alarmdown=0;
  210.             }
  211.             if (battlow) go_down_batt();
  212.         
  213.         }
  214.     }
  215.     if(killme == 1) {
  216.         syslog(LOG_INFO,"Ending apcd version %s",VERSION);
  217.         if(slave==2) {
  218.             tcsetattr(port,TCSANOW,&oldtio);
  219.             close(port);
  220.         }
  221.         if (slave==1) close(socketfd);
  222.         if (slave==2) {
  223.             for(i=0;i<num_slaves;i++) close(slavesocket[i]);
  224.         }
  225.         closelog();
  226.         if (slave == 1) fclose(UPSlogfile);
  227.     }
  228.     if(killme == 2) {
  229.         if(slave==2) send_to_slaves(-2);
  230.         mesall("APC Daemon: SYSTEM IS GOING DOWN NOW !!!");
  231.         if (slave==1) close(socketfd);
  232.         if (slave==2) {
  233.             for(i=0;i<num_slaves;i++) close(slavesocket[i]);
  234.         }
  235.         do_shutdown();
  236.     }
  237. };
  238.  
  239.  
  240. /* Setup of the communication port. Hope it will work
  241.  */
  242.  
  243. void setup_tty()
  244. {
  245.     port=open(use_port,O_RDWR | O_NOCTTY);
  246.     if (port < 0) {
  247.         syslog(LOG_ERR,"Unable to open port %s",use_port);
  248.         exit(-1);
  249.     }
  250.     tcgetattr(port,&oldtio); /* Save old settings */
  251.     newtio.c_cflag = DEFAULT_SPEED | CS8 | CLOCAL | CREAD;
  252.     newtio.c_iflag = IGNPAR; /* Ignore errors, raw input */
  253.     newtio.c_oflag = 0; /* Raw output */
  254.     newtio.c_lflag = 0; /* No local echo */    
  255.     newtio.c_cc[VMIN] = 1;
  256.     newtio.c_cc[VTIME] = 0;
  257.     tcflush(port,TCIFLUSH);
  258.     tcsetattr(port,TCSANOW,&newtio);
  259. }
  260.  
  261.  
  262. /* Become a daemon, release stdin, stdout etc.
  263.  */
  264.  
  265. void start_daemon()
  266. {
  267.     int    pid;
  268.     
  269.     close(0);
  270.     close(1);
  271.     close(2);
  272.     if ((pid=fork()) < 0) {
  273.         syslog(LOG_ERR,"Unable to fork");
  274.         exit(1);
  275.     }
  276.     if (pid != 0) exit(0);
  277. };
  278.  
  279.  
  280. /* Setup various signal handlers. Code here is adapted from diald program
  281.  * which is (c) Eric Schenk.
  282.  */
  283.  
  284. void signal_setup()
  285. {
  286.     sigset_t    sigmask;
  287.     struct    sigaction sa;
  288.     
  289.     sigemptyset(&sigmask);
  290.     sigaddset(&sigmask, SIGINT); /* Termination requested */
  291.     sigaddset(&sigmask, SIGTERM); /* Termination requested */
  292.     if(slave==2) sigaddset(&sigmask, SIGUSR1); /* Dump UPS stats */    
  293.     
  294. #define SIGNAL(s,handler) { \
  295.         sa.sa_handler = handler; \
  296.         if (sigaction(s, &sa, NULL) < 0) { \
  297.             syslog(LOG_ERR, "sigaction(%d) failed ", s); \
  298.             exit(1); \
  299.         } \
  300.     }
  301.  
  302.     sa.sa_mask = sigmask;
  303.     sa.sa_flags = 0;
  304.     SIGNAL(SIGINT,sig_intr);
  305.     SIGNAL(SIGTERM,sig_term);
  306.     if(slave==2) SIGNAL(SIGUSR1,dump_status);
  307.  
  308. }
  309.  
  310. void sig_intr(int sig)
  311. {
  312.     syslog(LOG_INFO,"SIGINTR Termination requested");
  313.     killme = 1;
  314. }    
  315.  
  316. void sig_term(int sig)
  317. {
  318.     syslog(LOG_INFO,"SIGTERM Termination requested");
  319.     killme=1;
  320. }    
  321.  
  322. void dump_status(int sig)
  323. {
  324.     valfile=fopen("/tmp/upsstat","w");
  325.     fprintf(valfile,"ULINE:%.1f\n",myUPS.LineVoltage);
  326.     fprintf(valfile,"MLINE:%.1f\n",myUPS.LineMax);
  327.     fprintf(valfile,"NLINE:%.1f\n",myUPS.LineMin);
  328.     fprintf(valfile,"FLINE:%.1f\n",myUPS.LineFreq);
  329.     fprintf(valfile,"VOUTP:%.1f\n",myUPS.OutputVoltage);
  330.     fprintf(valfile,"LOUTP:%.1f\n",myUPS.UPSLoad);
  331.     fprintf(valfile,"BOUTP:%.1f\n",myUPS.BattVoltage);
  332.     fprintf(valfile,"BCHAR:%.1f\n",myUPS.BatLoad);
  333.     fprintf(valfile,"BFAIL:%d\n",battlow);
  334.     fprintf(valfile,"UTEMP:%.1f\n",myUPS.UPSTemp);
  335.     if(pending) {
  336.         fprintf(valfile,"UBATT:1\n");
  337.         fprintf(valfile,"UPOWR:0\n");
  338.     }
  339.     else {
  340.         fprintf(valfile,"UBATT:0\n");
  341.         fprintf(valfile,"UPOWR:1\n");
  342.     };
  343.     fprintf(valfile,"UTST1:NONE\n");
  344.     fprintf(valfile,"UTST2:NONE\n");
  345.     fprintf(valfile,"UTST3:NONE\n");
  346.     fprintf(valfile,"UTST4:NONE\n");
  347.     fprintf(valfile,"UTST5:NONE\n");
  348.     fprintf(valfile,"UTST6:NONE\n");
  349.     fprintf(valfile,"UTST7:NONE\n");
  350.     fprintf(valfile,"UTST8:NONE\n");
  351.     fprintf(valfile,"UTST9:NONE\n");
  352.     fprintf(valfile,"UTST0:NONE\n");
  353.     fprintf(valfile,"UUSR1:NONE\n");
  354.     fprintf(valfile,"UUSR2:NONE\n");
  355.     fprintf(valfile,"UUSR3:NONE\n");
  356.     fprintf(valfile,"UUSR4:NONE\n");
  357.     fprintf(valfile,"UUSR5:NONE\n");
  358.     fprintf(valfile,"UUSR6:NONE\n");
  359.     fprintf(valfile,"UUSR7:NONE\n");
  360.     fprintf(valfile,"UUSR8:NONE\n");
  361.     fprintf(valfile,"UUSR9:NONE\n");
  362.     fprintf(valfile,"UUSR0:NONE\n");
  363.     fclose(valfile);
  364. }
  365.  
  366.  
  367. void go_down()
  368. {
  369.     syslog(LOG_INFO,"System is going down - power failure");
  370.     killme=2;
  371. }
  372.  
  373. void go_down_batt()
  374. {
  375.     syslog(LOG_INFO,"System is going down - battery low");
  376.     killme=2; 
  377. }
  378.  
  379.  
  380. int getline(int fd, char *s)
  381. {
  382.     int i,ending;
  383.     char c;
  384.     
  385.     i=0;
  386.     ending=0;
  387.     
  388.     while (!ending) {
  389.         read(fd,&c,1);
  390.         switch(c) {
  391.             case UPS_ON_BATT: syslog(LOG_INFO,"UPS is going on battery");
  392.                               alarmup=1;
  393.                         break;
  394.             case UPS_ON_LINE: syslog(LOG_INFO,"UPS is going on-line");
  395.                               alarmdown=1;
  396.                       break;
  397.             case     BATT_LOW: battlow=1;
  398.                       break;
  399.             case     BATT_OK: battlow=0;
  400.                       break;
  401.             case         '\n': ending=1;
  402.                       break;
  403.                  default: s[i++]=c;
  404.                        break;
  405.         }
  406.     }
  407.     s[i]='\0';
  408.     return(0);
  409. }
  410.  
  411. int fillUPS (int fd,UPSINFO *ups)
  412. {
  413.     char    answer[MAXLINE];
  414.     char    q;
  415.  
  416.     q='Y';
  417.     write(fd,&q,1);
  418.     getline(fd,answer);
  419.     
  420.     q=BATT_FULL;
  421.     write(fd,&q,1);
  422.     getline(fd,answer);
  423.     ups->BatLoad=atof(answer);
  424.     
  425.     q=UPS_LINE_MIN;
  426.     write(fd,&q,1);
  427.     getline(fd,answer);
  428.     ups->LineMin=atof(answer);
  429.     
  430.     q=UPS_LINE_MAX;
  431.     write(fd,&q,1);
  432.     getline(fd,answer);
  433.     ups->LineMax=atof(answer);
  434.     
  435.     q=UPS_LOAD;
  436.     write(fd,&q,1);
  437.     getline(fd,answer);
  438.     ups->UPSLoad=atof(answer);
  439.     
  440.     q=LINE_FREQ;
  441.     write(fd,&q,1);
  442.     getline(fd,answer);
  443.     ups->LineFreq=atof(answer);
  444.     
  445.     q=LINE_VOLTAGE;
  446.     write(fd,&q,1);
  447.     getline(fd,answer);
  448.     ups->LineVoltage=atof(answer);
  449.     
  450.     q=OUTPUT_VOLTAGE;
  451.     write(fd,&q,1);
  452.     getline(fd,answer);
  453.     ups->OutputVoltage=atof(answer);
  454.     
  455.     q=UPS_TEMP;
  456.     write(fd,&q,1);
  457.     getline(fd,answer);
  458.     ups->UPSTemp=atof(answer);
  459.     
  460.     q=BATT_VOLTAGE;
  461.     write(fd,&q,1);
  462.     getline(fd,answer);
  463.     ups->BattVoltage=atof(answer);
  464.     
  465.     q=UPS_STATUS;
  466.     write(fd,&q,1);
  467.     getline(fd,answer);
  468.     ups->Status=atoi(answer);
  469.  
  470.     log_counter++;
  471.     if(log_counter >= log_timer) {
  472.         log_counter=0;
  473.         log_UPS_status();
  474.     }    
  475.     return(0);
  476. }        
  477.  
  478.  
  479. /* mesusr() and mesall() function are actually parts of shutdown source
  480.  * I am using them for sending messages before shutdown
  481.  */
  482.  
  483. void mesusr(char *mess,struct utmp *ut)
  484. {
  485.     int fd;
  486.     char term[40] = {'/','d','e','v','/',0};
  487.  
  488.     (void)strncat(term,ut->ut_line,sizeof(ut->ut_line));
  489.     if((fd=open(term, O_RDWR | O_NONBLOCK)) < 0)
  490.         return;
  491.     write(fd,mess,strlen(mess));
  492.     close(fd);
  493. }
  494.  
  495. void mesall(char *mess)
  496. {
  497.     struct utmp *ut;
  498.     utmpname(_PATH_UTMP);
  499.     setutent(); 
  500.     ut=getutent();
  501.     while((ut = getutent())) {
  502.         if(ut->ut_type == USER_PROCESS)
  503.             mesusr(mess,ut);
  504.     }
  505.     endutent();
  506. }
  507.  
  508.  
  509. /*
  510.  *
  511.  * From here, there are parts of the source from shutdown.c which
  512.  * is a part of linux-utils-2.1
  513.  *
  514.  */
  515.  
  516. void write_wtmp(), unmount_disks(), unmount_disks_ourselves();
  517.  
  518.  
  519.  
  520. void
  521. do_shutdown()
  522. {
  523. /*    struct itimerval new,old; */
  524.     char a;
  525.     
  526. /*    setpriority(PRIO_PROCESS, 0, PRIO_MIN); */
  527.  
  528.     chdir("/");
  529.  
  530.     signal(SIGPIPE, SIG_IGN);
  531.     signal(SIGINT,  SIG_IGN);
  532.  
  533.     /* do syslog message... */
  534.     syslog(LOG_INFO, "System cleanup"); 
  535.     closelog();
  536.     if (slave == 2) fclose(UPSlogfile);
  537.     sleep(1);
  538.     kill(1, SIGTSTP);    /* tell init not to spawn more getty's */
  539.     write_wtmp();
  540.     sync();
  541.     signal(SIGTERM, SIG_IGN);
  542.     setpgrp();        /* so the shell wont kill us in the fall */
  543.     /* a gentle kill of all other processes except init */
  544.     kill(-1, SIGTERM);
  545.     sleep(2);
  546.  
  547.     /* now use brute force... */
  548.     kill(-1, SIGKILL);
  549.  
  550.     /* turn off accounting */
  551.     acct(NULL);
  552.  
  553.     sync();
  554.     sleep(2);
  555.     /* unmount disks... */
  556.     unmount_disks();
  557.     sync();
  558.     sleep(1);
  559.     a = 'S';
  560.     if(slave==2) write(port,&a,1);
  561.     sleep(9999);    /* Wait for UPS switch off */    
  562.     reboot(0xfee1dead,672274793,0x1234567); /* Just for sure :-) */        
  563.     /* NOTREACHED */
  564.     exit(0); /* to quiet gcc */
  565. }
  566.  
  567.  
  568. void
  569. write_wtmp()
  570. {
  571.     /* write in wtmp that we are dying */
  572.     int fd;
  573.     struct utmp ut;
  574.     
  575.     memset((char *)&ut, 0, sizeof(ut));
  576.     strcpy(ut.ut_line, "~");
  577.     memcpy(ut.ut_name, "shutdown", sizeof(ut.ut_name));
  578.  
  579.     time(&ut.ut_time);
  580.     ut.ut_type = BOOT_TIME;
  581.     
  582.     if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) > 0) {
  583.         write(fd, (char *)&ut, sizeof(ut));
  584.         close(fd);
  585.     }
  586. }
  587.  
  588. void
  589. unmount_disks()
  590. {
  591.     /* better to use umount directly because it may be smarter than us */
  592.  
  593.     int pid;
  594.     int result;
  595.     int status;
  596.  
  597.     sync();
  598.     if ((pid = fork()) < 0) {
  599.         printf("Cannot fork for umount, trying manually.\n");
  600.         unmount_disks_ourselves();
  601.         return;
  602.     }
  603.     if (!pid) {
  604.         execl(_PATH_UMOUNT, UMOUNT_ARGS, NULL);
  605.         printf("Cannot exec %s, trying umount.\n", _PATH_UMOUNT);
  606.         execlp("umount", UMOUNT_ARGS, NULL);
  607.         printf("Cannot exec umount, trying manually.\n");
  608.         unmount_disks_ourselves();
  609.         exit(0);
  610.     }
  611.     while ((result = wait(&status)) != -1 && result != pid)
  612.         ;
  613.     if (result == -1 || status) {
  614.         printf("Running umount failed, trying manually.\n");
  615.         unmount_disks_ourselves();
  616.     }
  617. }
  618.  
  619. void
  620. unmount_disks_ourselves()
  621. {
  622.     /* unmount all disks */
  623.  
  624.     FILE *mtab;
  625.     struct mntent *mnt;
  626.     char *mntlist[128];
  627.     int i;
  628.     int n;
  629.     char *filesys;
  630.     
  631.     sync();
  632.     if (!(mtab = setmntent(_PATH_MTAB, "r"))) {
  633.         printf("Cannot open %s.\n", _PATH_MTAB);
  634.         return;
  635.     }
  636.     n = 0;
  637.     while (n < 100 && (mnt = getmntent(mtab))) {
  638.         mntlist[n++] = strdup(mnt->mnt_fsname[0] == '/' ?
  639.             mnt->mnt_fsname : mnt->mnt_dir);
  640.     }
  641.     endmntent(mtab);
  642.  
  643.     /* we are careful to do this in reverse order of the mtab file */
  644.  
  645.     for (i = n - 1; i >= 0; i--) {
  646.         filesys = mntlist[i];
  647. #ifdef DEBUGGING
  648.         printf("umount %s\n", filesys);
  649. #else
  650.         if (umount(mntlist[i]) < 0)
  651.             printf("Couldn't umount %s\n", filesys);
  652. #endif
  653.     }
  654. }
  655.  
  656. void log_UPS_status()
  657. {
  658.     char msg[100];
  659.     time_t    nowtime;
  660.  
  661.     time(&nowtime);
  662.     strftime(msg,100,"%b %d %X",localtime(&nowtime));
  663.     fprintf(UPSlogfile,"%s APC: ",msg);
  664.     fprintf(UPSlogfile,"%.1f %.1f %.1f ",myUPS.BatLoad,myUPS.LineMin,myUPS.LineMax);
  665.     fprintf(UPSlogfile,"%.1f %.1f %.1f ",myUPS.UPSLoad,myUPS.LineFreq,myUPS.LineVoltage);
  666.     fprintf(UPSlogfile,"%.1f %.1f %.1f\n",myUPS.OutputVoltage,myUPS.UPSTemp,myUPS.BattVoltage);
  667.     fflush(UPSlogfile);
  668. }
  669.  
  670.  
  671.